﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebApi.Core.Common.Helper;

namespace WebApi.Core.SetUp
{
    /// <summary>
    /// JWT授权认证
    /// </summary>
    public static class AuthorizationSetup
    {
        public static void AddAuthorizationSetup(this IServiceCollection services)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));

            //1【授权】角色策略、这个和上边的异曲同工，好处就是不用在controller中，写多个roles-->eq:SystemOrAdmin 。
            //然后这么写[Authorize(Policy="Admin")]
            //可以对不同的角色建立不同的策略
            services.AddAuthorization(options =>
            {
                options.AddPolicy("User", policy => policy.RequireRole("User").Build());
                options.AddPolicy("SystemOrAdmin",policy => policy.RequireRole("Admin","System"));
            });

            //读取配置文件
            var symmetricKeyAsBase64 = AppSettings.app(new string[] { "AppSettings","JwtSetting","SecretKey"});
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var Issuer = AppSettings.app(new string[] { "AppSettings","JwtSetting","Issuer"});
            var Audience = AppSettings.app(new string[] { "AppSettings","JwtSetting","Audience"});

            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,//是否验证签名,不验证的话可以篡改数据，不安全
                IssuerSigningKey = signingKey,  //解密的密钥
                ValidateIssuer = true,   //是否验证发行人，就是验证载荷中的Iss是否对应ValidIssuer参数
                ValidIssuer = Issuer,//发行人(√)
                ValidateAudience = true,  //是否验证订阅人，就是验证载荷中的Aud是否对应ValidAudience参数
                ValidAudience = Audience,//订阅人(√)
                ValidateLifetime = true,  //是否验证过期时间，过期了就拒绝访问
                ClockSkew = TimeSpan.FromSeconds(30),  //这个是缓冲过期时间，也就是说，即使我们配置了过期时间，这里也要考虑进去，过期时间+缓冲，默认好像是7分钟，你可以直接设置为0
                RequireExpirationTime = true,
            };

            //2.1【认证】、core自带官方JWT认证
            // 开启Bearer认证
            services.AddAuthentication("Bearer")
             // 添加JwtBearer服务
             .AddJwtBearer(o =>
             {
                 o.TokenValidationParameters = tokenValidationParameters;
                 o.Events = new JwtBearerEvents
                 {
                     OnAuthenticationFailed = context =>
                     {
                         // 如果过期，则把<是否过期>添加到，返回头信息中
                         if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                         {
                             context.Response.Headers.Add("Token-Expired", "true");
                         }
                         return Task.CompletedTask;
                     }
                 };
             });

        }


    }
}
